tiny_xml_builder 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .raketasks
2
+ announcement.txt
3
+ coverage
4
+ doc
5
+ pkg
data/History.txt ADDED
@@ -0,0 +1,14 @@
1
+ == 0.0.3 / 2011-02-04
2
+ * 2 more enhancements
3
+ * Using the blankslate gem now for our blankslating needs (instead of embedding it);
4
+ * Tested and working against Ruby {1.8.7, 1.9.2} and JRuby {1.5.6}
5
+
6
+ == 0.0.2 / 2011-02-03
7
+
8
+ * 1 other major enhancement
9
+ * Finally ready for release :-)
10
+
11
+ == 0.0.1 / 2010-10-28
12
+
13
+ * 1 major enhancement
14
+ * Birthday!
data/README.asciidoc ADDED
@@ -0,0 +1,156 @@
1
+ Tiny XML Builder
2
+ ================
3
+ Alexandru Ungur <alexaandru@gmail.com>
4
+ :icons:
5
+ :toc:
6
+ :website: http://github.com/alexaandru/tiny_xml_builder
7
+
8
+ Description
9
+ -----------
10
+
11
+ A very simple XML builder class. +
12
+ I wanted something really simple that I could easily extend myself later on if I needed to. +
13
+ Ironically, in four years since I created and used TinyXml, I never needed to extend it :-)
14
+ I figured, it may as well work for others in that case, so here it is.
15
+
16
+ Acknowledgements
17
+ ----------------
18
+
19
+ A big thanks to Jim Weirich for his great advices on Ruby-talk. +
20
+ The BlankSlate "mechanism" he describes at: http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc
21
+ and which this library depends upon, is one of the first things I've learnt when started to play with Ruby DSLs.
22
+
23
+ Features/Problems
24
+ -----------------
25
+ - You cannot have XML elements named _\__id\___, _\__send___, _method_missing_, _instance_eval_ or _respond_to_ as those are NOT undefined (on purpose) by BlankSlate mechanism;
26
+ - There are other limitations related to ``implicit receiver'' calls, e.g.:
27
+
28
+ .Explicit receiver example
29
+ ---------------------------------------------
30
+ puts TinyXml::Builder.new.foo {|f| f.p 'bar'}
31
+ ---------------------------------------------
32
+
33
+ will output:
34
+
35
+ ------------
36
+ <foo>
37
+ <p>bar</p>
38
+ </foo>
39
+ ------------
40
+
41
+ while the following:
42
+
43
+ .Implicit receiver example
44
+ -----------------------------------------
45
+ puts TinyXml::Builder.new.foo { p 'bar' }
46
+ -----------------------------------------
47
+
48
+ will output:
49
+
50
+ ------
51
+ "bar"
52
+ <foo>
53
+ </foo>
54
+ ------
55
+
56
+ as "p" method exists in outer scope and does an entirely different thing than what (missing) methods of TinyXml do.
57
+
58
+ Synopsis
59
+ --------
60
+
61
+ .Example Usage
62
+ -----------------------------------------------------------------------------------------
63
+ builder = TinyXml::Builder.new
64
+ builder.html do |xhtml|
65
+ xhtml.head do |head|
66
+ head.title 'Hello World'
67
+ head.meta :name => :keywords, :content => 'hello, world'
68
+ head.meta :name => :description, :content => 'hello world sample usage for XML class'
69
+ end
70
+ xhtml.body do |body|
71
+ body.div :id => 'main' do |div_main|
72
+ div_main.h1 "Hello World"
73
+ div_main.p "Hello HTML world", "from XML"
74
+ end
75
+ end
76
+ end
77
+
78
+ puts builder
79
+ -----------------------------------------------------------------------------------------
80
+
81
+ .Alternate Example Usage
82
+ -----------------------------------------------------------------------------------------
83
+ puts TinyXml::Builder.new.html {
84
+ head {
85
+ title 'Hello World'
86
+ meta :name => :keywords, :content => 'hello, world'
87
+ meta :name => :description, :content => 'hello world sample usage for XML class'
88
+ }
89
+
90
+ body {
91
+ div(:id => 'main') { |div|
92
+ div.h1 "Hello World"
93
+ div.p "Hello HTML world", "from XML"
94
+ }
95
+ }
96
+ }
97
+ -----------------------------------------------------------------------------------------
98
+
99
+ both will output:
100
+
101
+ -----------------------------------------------------------------------------------------
102
+ <html>
103
+ <head>
104
+ <title>Hello World</title>
105
+ <meta name="keywords" content="hello, world" />
106
+ <meta name="description" content="hello world sample usage for XML class" />
107
+ </head>
108
+ <body>
109
+ <div id="main">
110
+ <h1>Hello World</h1>
111
+ <p>Hello HTML world</p>
112
+ <p>from XML</p>
113
+ </div>
114
+ </body>
115
+ </html>
116
+ -----------------------------------------------------------------------------------------
117
+
118
+ Requirements
119
+ ------------
120
+
121
+ NONE
122
+
123
+ Install
124
+ -------
125
+
126
+ *********************************
127
+ sudo gem install tiny_xml_builder
128
+ *********************************
129
+
130
+ License
131
+ -------
132
+
133
+ (The MIT License)
134
+
135
+ Copyright (c) 2010 Alexandru Ungur
136
+
137
+ Permission is hereby granted, free of charge, to any person obtaining
138
+ a copy of this software and associated documentation files (the
139
+ 'Software'), to deal in the Software without restriction, including
140
+ without limitation the rights to use, copy, modify, merge, publish,
141
+ distribute, sublicense, and/or sell copies of the Software, and to
142
+ permit persons to whom the Software is furnished to do so, subject to
143
+ the following conditions:
144
+
145
+ The above copyright notice and this permission notice shall be
146
+ included in all copies or substantial portions of the Software.
147
+
148
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
149
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
150
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
151
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
152
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
153
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
154
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
155
+
156
+ // vim: set syntax=asciidoc:
data/README.html ADDED
@@ -0,0 +1,682 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
2
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
6
+ <meta name="generator" content="AsciiDoc 8.6.3" />
7
+ <title>Tiny XML Builder</title>
8
+ <style type="text/css">
9
+ /* Debug borders */
10
+ p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
11
+ /*
12
+ border: 1px solid red;
13
+ */
14
+ }
15
+
16
+ body {
17
+ margin: 1em 5% 1em 5%;
18
+ }
19
+
20
+ a {
21
+ color: blue;
22
+ text-decoration: underline;
23
+ }
24
+ a:visited {
25
+ color: fuchsia;
26
+ }
27
+
28
+ em {
29
+ font-style: italic;
30
+ color: navy;
31
+ }
32
+
33
+ strong {
34
+ font-weight: bold;
35
+ color: #083194;
36
+ }
37
+
38
+ tt {
39
+ color: navy;
40
+ }
41
+
42
+ h1, h2, h3, h4, h5, h6 {
43
+ color: #527bbd;
44
+ font-family: sans-serif;
45
+ margin-top: 1.2em;
46
+ margin-bottom: 0.5em;
47
+ line-height: 1.3;
48
+ }
49
+
50
+ h1, h2, h3 {
51
+ border-bottom: 2px solid silver;
52
+ }
53
+ h2 {
54
+ padding-top: 0.5em;
55
+ }
56
+ h3 {
57
+ float: left;
58
+ }
59
+ h3 + * {
60
+ clear: left;
61
+ }
62
+
63
+ div.sectionbody {
64
+ font-family: serif;
65
+ margin-left: 0;
66
+ }
67
+
68
+ hr {
69
+ border: 1px solid silver;
70
+ }
71
+
72
+ p {
73
+ margin-top: 0.5em;
74
+ margin-bottom: 0.5em;
75
+ }
76
+
77
+ ul, ol, li > p {
78
+ margin-top: 0;
79
+ }
80
+
81
+ pre {
82
+ padding: 0;
83
+ margin: 0;
84
+ }
85
+
86
+ span#author {
87
+ color: #527bbd;
88
+ font-family: sans-serif;
89
+ font-weight: bold;
90
+ font-size: 1.1em;
91
+ }
92
+ span#email {
93
+ }
94
+ span#revnumber, span#revdate, span#revremark {
95
+ font-family: sans-serif;
96
+ }
97
+
98
+ div#footer {
99
+ font-family: sans-serif;
100
+ font-size: small;
101
+ border-top: 2px solid silver;
102
+ padding-top: 0.5em;
103
+ margin-top: 4.0em;
104
+ }
105
+ div#footer-text {
106
+ float: left;
107
+ padding-bottom: 0.5em;
108
+ }
109
+ div#footer-badges {
110
+ float: right;
111
+ padding-bottom: 0.5em;
112
+ }
113
+
114
+ div#preamble {
115
+ margin-top: 1.5em;
116
+ margin-bottom: 1.5em;
117
+ }
118
+ div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
119
+ div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
120
+ div.admonitionblock {
121
+ margin-top: 0.25em;
122
+ margin-bottom: 1.5em;
123
+ }
124
+ div.admonitionblock {
125
+ margin-top: 2.5em;
126
+ margin-bottom: 2.5em;
127
+ }
128
+
129
+ div.content { /* Block element content. */
130
+ padding: 0;
131
+ }
132
+
133
+ /* Block element titles. */
134
+ div.title, caption.title {
135
+ color: #527bbd;
136
+ font-family: sans-serif;
137
+ font-weight: bold;
138
+ text-align: left;
139
+ margin-top: 1.0em;
140
+ margin-bottom: 0.5em;
141
+ }
142
+ div.title + * {
143
+ margin-top: 0;
144
+ }
145
+
146
+ td div.title:first-child {
147
+ margin-top: 0.0em;
148
+ }
149
+ div.content div.title:first-child {
150
+ margin-top: 0.0em;
151
+ }
152
+ div.content + div.title {
153
+ margin-top: 0.0em;
154
+ }
155
+
156
+ div.sidebarblock > div.content {
157
+ background: #ffffee;
158
+ border: 1px solid silver;
159
+ padding: 0.5em;
160
+ }
161
+
162
+ div.listingblock > div.content {
163
+ border: 1px solid silver;
164
+ background: #f4f4f4;
165
+ padding: 0.5em;
166
+ }
167
+
168
+ div.quoteblock {
169
+ padding-left: 2.0em;
170
+ margin-right: 10%;
171
+ }
172
+ div.quoteblock > div.attribution {
173
+ padding-top: 0.5em;
174
+ text-align: right;
175
+ }
176
+
177
+ div.verseblock {
178
+ padding-left: 2.0em;
179
+ margin-right: 10%;
180
+ }
181
+ div.verseblock > div.content {
182
+ white-space: pre;
183
+ }
184
+ div.verseblock > div.attribution {
185
+ padding-top: 0.75em;
186
+ text-align: left;
187
+ }
188
+ /* DEPRECATED: Pre version 8.2.7 verse style literal block. */
189
+ div.verseblock + div.attribution {
190
+ text-align: left;
191
+ }
192
+
193
+ div.admonitionblock .icon {
194
+ vertical-align: top;
195
+ font-size: 1.1em;
196
+ font-weight: bold;
197
+ text-decoration: underline;
198
+ color: #527bbd;
199
+ padding-right: 0.5em;
200
+ }
201
+ div.admonitionblock td.content {
202
+ padding-left: 0.5em;
203
+ border-left: 2px solid silver;
204
+ }
205
+
206
+ div.exampleblock > div.content {
207
+ border-left: 2px solid silver;
208
+ padding: 0.5em;
209
+ }
210
+
211
+ div.imageblock div.content { padding-left: 0; }
212
+ span.image img { border-style: none; }
213
+ a.image:visited { color: white; }
214
+
215
+ dl {
216
+ margin-top: 0.8em;
217
+ margin-bottom: 0.8em;
218
+ }
219
+ dt {
220
+ margin-top: 0.5em;
221
+ margin-bottom: 0;
222
+ font-style: normal;
223
+ color: navy;
224
+ }
225
+ dd > *:first-child {
226
+ margin-top: 0.1em;
227
+ }
228
+
229
+ ul, ol {
230
+ list-style-position: outside;
231
+ }
232
+ ol.arabic {
233
+ list-style-type: decimal;
234
+ }
235
+ ol.loweralpha {
236
+ list-style-type: lower-alpha;
237
+ }
238
+ ol.upperalpha {
239
+ list-style-type: upper-alpha;
240
+ }
241
+ ol.lowerroman {
242
+ list-style-type: lower-roman;
243
+ }
244
+ ol.upperroman {
245
+ list-style-type: upper-roman;
246
+ }
247
+
248
+ div.compact ul, div.compact ol,
249
+ div.compact p, div.compact p,
250
+ div.compact div, div.compact div {
251
+ margin-top: 0.1em;
252
+ margin-bottom: 0.1em;
253
+ }
254
+
255
+ div.tableblock > table {
256
+ border: 3px solid #527bbd;
257
+ }
258
+ thead {
259
+ font-family: sans-serif;
260
+ font-weight: bold;
261
+ }
262
+ tfoot {
263
+ font-weight: bold;
264
+ }
265
+ td > div.verse {
266
+ white-space: pre;
267
+ }
268
+ p.table {
269
+ margin-top: 0;
270
+ }
271
+ /* Because the table frame attribute is overriden by CSS in most browsers. */
272
+ div.tableblock > table[frame="void"] {
273
+ border-style: none;
274
+ }
275
+ div.tableblock > table[frame="hsides"] {
276
+ border-left-style: none;
277
+ border-right-style: none;
278
+ }
279
+ div.tableblock > table[frame="vsides"] {
280
+ border-top-style: none;
281
+ border-bottom-style: none;
282
+ }
283
+
284
+
285
+ div.hdlist {
286
+ margin-top: 0.8em;
287
+ margin-bottom: 0.8em;
288
+ }
289
+ div.hdlist tr {
290
+ padding-bottom: 15px;
291
+ }
292
+ dt.hdlist1.strong, td.hdlist1.strong {
293
+ font-weight: bold;
294
+ }
295
+ td.hdlist1 {
296
+ vertical-align: top;
297
+ font-style: normal;
298
+ padding-right: 0.8em;
299
+ color: navy;
300
+ }
301
+ td.hdlist2 {
302
+ vertical-align: top;
303
+ }
304
+ div.hdlist.compact tr {
305
+ margin: 0;
306
+ padding-bottom: 0;
307
+ }
308
+
309
+ .comment {
310
+ background: yellow;
311
+ }
312
+
313
+ .footnote, .footnoteref {
314
+ font-size: 0.8em;
315
+ }
316
+
317
+ span.footnote, span.footnoteref {
318
+ vertical-align: super;
319
+ }
320
+
321
+ #footnotes {
322
+ margin: 20px 0 20px 0;
323
+ padding: 7px 0 0 0;
324
+ }
325
+
326
+ #footnotes div.footnote {
327
+ margin: 0 0 5px 0;
328
+ }
329
+
330
+ #footnotes hr {
331
+ border: none;
332
+ border-top: 1px solid silver;
333
+ height: 1px;
334
+ text-align: left;
335
+ margin-left: 0;
336
+ width: 20%;
337
+ min-width: 100px;
338
+ }
339
+
340
+
341
+ @media print {
342
+ div#footer-badges { display: none; }
343
+ }
344
+
345
+ div#toctitle {
346
+ color: #527bbd;
347
+ font-family: sans-serif;
348
+ font-size: 1.1em;
349
+ font-weight: bold;
350
+ margin-top: 1.0em;
351
+ margin-bottom: 0.1em;
352
+ }
353
+
354
+ div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
355
+ margin-top: 0;
356
+ margin-bottom: 0;
357
+ }
358
+ div.toclevel2 {
359
+ margin-left: 2em;
360
+ font-size: 0.9em;
361
+ }
362
+ div.toclevel3 {
363
+ margin-left: 4em;
364
+ font-size: 0.9em;
365
+ }
366
+ div.toclevel4 {
367
+ margin-left: 6em;
368
+ font-size: 0.9em;
369
+ }
370
+ </style>
371
+ <script type="text/javascript">
372
+ /*<![CDATA[*/
373
+ window.onload = function(){asciidoc.footnotes(); asciidoc.toc(2);}
374
+ var asciidoc = { // Namespace.
375
+
376
+ /////////////////////////////////////////////////////////////////////
377
+ // Table Of Contents generator
378
+ /////////////////////////////////////////////////////////////////////
379
+
380
+ /* Author: Mihai Bazon, September 2002
381
+ * http://students.infoiasi.ro/~mishoo
382
+ *
383
+ * Table Of Content generator
384
+ * Version: 0.4
385
+ *
386
+ * Feel free to use this script under the terms of the GNU General Public
387
+ * License, as long as you do not remove or alter this notice.
388
+ */
389
+
390
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
391
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
392
+
393
+ // toclevels = 1..4.
394
+ toc: function (toclevels) {
395
+
396
+ function getText(el) {
397
+ var text = "";
398
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
399
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
400
+ text += i.data;
401
+ else if (i.firstChild != null)
402
+ text += getText(i);
403
+ }
404
+ return text;
405
+ }
406
+
407
+ function TocEntry(el, text, toclevel) {
408
+ this.element = el;
409
+ this.text = text;
410
+ this.toclevel = toclevel;
411
+ }
412
+
413
+ function tocEntries(el, toclevels) {
414
+ var result = new Array;
415
+ var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
416
+ // Function that scans the DOM tree for header elements (the DOM2
417
+ // nodeIterator API would be a better technique but not supported by all
418
+ // browsers).
419
+ var iterate = function (el) {
420
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
421
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
422
+ var mo = re.exec(i.tagName);
423
+ if (mo)
424
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
425
+ iterate(i);
426
+ }
427
+ }
428
+ }
429
+ iterate(el);
430
+ return result;
431
+ }
432
+
433
+ var toc = document.getElementById("toc");
434
+ var entries = tocEntries(document.getElementById("content"), toclevels);
435
+ for (var i = 0; i < entries.length; ++i) {
436
+ var entry = entries[i];
437
+ if (entry.element.id == "")
438
+ entry.element.id = "_toc_" + i;
439
+ var a = document.createElement("a");
440
+ a.href = "#" + entry.element.id;
441
+ a.appendChild(document.createTextNode(entry.text));
442
+ var div = document.createElement("div");
443
+ div.appendChild(a);
444
+ div.className = "toclevel" + entry.toclevel;
445
+ toc.appendChild(div);
446
+ }
447
+ if (entries.length == 0)
448
+ toc.parentNode.removeChild(toc);
449
+ },
450
+
451
+
452
+ /////////////////////////////////////////////////////////////////////
453
+ // Footnotes generator
454
+ /////////////////////////////////////////////////////////////////////
455
+
456
+ /* Based on footnote generation code from:
457
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
458
+ */
459
+
460
+ footnotes: function () {
461
+ var cont = document.getElementById("content");
462
+ var noteholder = document.getElementById("footnotes");
463
+ var spans = cont.getElementsByTagName("span");
464
+ var refs = {};
465
+ var n = 0;
466
+ for (i=0; i<spans.length; i++) {
467
+ if (spans[i].className == "footnote") {
468
+ n++;
469
+ // Use [\s\S] in place of . so multi-line matches work.
470
+ // Because JavaScript has no s (dotall) regex flag.
471
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
472
+ noteholder.innerHTML +=
473
+ "<div class='footnote' id='_footnote_" + n + "'>" +
474
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
475
+ n + "</a>. " + note + "</div>";
476
+ spans[i].innerHTML =
477
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
478
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
479
+ var id =spans[i].getAttribute("id");
480
+ if (id != null) refs["#"+id] = n;
481
+ }
482
+ }
483
+ if (n == 0)
484
+ noteholder.parentNode.removeChild(noteholder);
485
+ else {
486
+ // Process footnoterefs.
487
+ for (i=0; i<spans.length; i++) {
488
+ if (spans[i].className == "footnoteref") {
489
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
490
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
491
+ n = refs[href];
492
+ spans[i].innerHTML =
493
+ "[<a href='#_footnote_" + n +
494
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
495
+ }
496
+ }
497
+ }
498
+ }
499
+
500
+ }
501
+ /*]]>*/
502
+ </script>
503
+ </head>
504
+ <body class="article">
505
+ <div id="header">
506
+ <h1>Tiny XML Builder</h1>
507
+ <span id="author">Alexandru Ungur</span><br />
508
+ <span id="email"><tt>&lt;<a href="mailto:alexaandru@gmail.com">alexaandru@gmail.com</a>&gt;</tt></span><br />
509
+ <div id="toc">
510
+ <div id="toctitle">Table of Contents</div>
511
+ <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
512
+ </div>
513
+ </div>
514
+ <div id="content">
515
+ <div class="sect1">
516
+ <h2 id="_description">Description</h2>
517
+ <div class="sectionbody">
518
+ <div class="paragraph"><p>A very simple XML builder class.<br />
519
+ I wanted something really simple that I could easily extend myself later on if I needed to.<br />
520
+ Ironically, in four years since I created and used TinyXml, I never needed to extend it :-)
521
+ I figured, it may as well work for others in that case, so here it is.</p></div>
522
+ </div>
523
+ </div>
524
+ <div class="sect1">
525
+ <h2 id="_acknowledgements">Acknowledgements</h2>
526
+ <div class="sectionbody">
527
+ <div class="paragraph"><p>A big thanks to Jim Weirich for his great advices on Ruby-talk.<br />
528
+ The BlankSlate "mechanism" he describes at: <a href="http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc">http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc</a>
529
+ and which this library depends upon, is one of the first things I&#8217;ve learnt when started to play with Ruby DSLs.</p></div>
530
+ </div>
531
+ </div>
532
+ <div class="sect1">
533
+ <h2 id="_features_problems">Features/Problems</h2>
534
+ <div class="sectionbody">
535
+ <div class="ulist"><ul>
536
+ <li>
537
+ <p>
538
+ You cannot have XML elements named <em>__id__</em>, <em>__send__</em>, <em>method_missing</em>, <em>instance_eval</em> or <em>respond_to</em> as those are NOT undefined (on purpose) by BlankSlate mechanism;
539
+ </p>
540
+ </li>
541
+ <li>
542
+ <p>
543
+ There are other limitations related to &#8220;implicit receiver&#8221; calls, e.g.:
544
+ </p>
545
+ </li>
546
+ </ul></div>
547
+ <div class="listingblock">
548
+ <div class="title">Explicit receiver example</div>
549
+ <div class="content">
550
+ <pre><tt>puts TinyXml::Builder.new.foo {|f| f.p 'bar'}</tt></pre>
551
+ </div></div>
552
+ <div class="paragraph"><p>will output:</p></div>
553
+ <div class="listingblock">
554
+ <div class="content">
555
+ <pre><tt>&lt;foo&gt;
556
+ &lt;p&gt;bar&lt;/p&gt;
557
+ &lt;/foo&gt;</tt></pre>
558
+ </div></div>
559
+ <div class="paragraph"><p>while the following:</p></div>
560
+ <div class="listingblock">
561
+ <div class="title">Implicit receiver example</div>
562
+ <div class="content">
563
+ <pre><tt>puts TinyXml::Builder.new.foo { p 'bar' }</tt></pre>
564
+ </div></div>
565
+ <div class="paragraph"><p>will output:</p></div>
566
+ <div class="listingblock">
567
+ <div class="content">
568
+ <pre><tt>"bar"
569
+ &lt;foo&gt;
570
+ &lt;/foo&gt;</tt></pre>
571
+ </div></div>
572
+ <div class="paragraph"><p>as "p" method exists in outer scope and does an entirely different thing than what (missing) methods of TinyXml do.</p></div>
573
+ </div>
574
+ </div>
575
+ <div class="sect1">
576
+ <h2 id="_synopsis">Synopsis</h2>
577
+ <div class="sectionbody">
578
+ <div class="listingblock">
579
+ <div class="title">Example Usage</div>
580
+ <div class="content">
581
+ <pre><tt>builder = TinyXml::Builder.new
582
+ builder.html do |xhtml|
583
+ xhtml.head do |head|
584
+ head.title 'Hello World'
585
+ head.meta :name =&gt; :keywords, :content =&gt; 'hello, world'
586
+ head.meta :name =&gt; :description, :content =&gt; 'hello world sample usage for XML class'
587
+ end
588
+ xhtml.body do |body|
589
+ body.div :id =&gt; 'main' do |div_main|
590
+ div_main.h1 "Hello World"
591
+ div_main.p "Hello HTML world", "from XML"
592
+ end
593
+ end
594
+ end
595
+
596
+ puts builder</tt></pre>
597
+ </div></div>
598
+ <div class="listingblock">
599
+ <div class="title">Alternate Example Usage</div>
600
+ <div class="content">
601
+ <pre><tt>puts TinyXml::Builder.new.html {
602
+ head {
603
+ title 'Hello World'
604
+ meta :name =&gt; :keywords, :content =&gt; 'hello, world'
605
+ meta :name =&gt; :description, :content =&gt; 'hello world sample usage for XML class'
606
+ }
607
+
608
+ body {
609
+ div(:id =&gt; 'main') { |div|
610
+ div.h1 "Hello World"
611
+ div.p "Hello HTML world", "from XML"
612
+ }
613
+ }
614
+ }</tt></pre>
615
+ </div></div>
616
+ <div class="paragraph"><p>both will output:</p></div>
617
+ <div class="listingblock">
618
+ <div class="content">
619
+ <pre><tt>&lt;html&gt;
620
+ &lt;head&gt;
621
+ &lt;title&gt;Hello World&lt;/title&gt;
622
+ &lt;meta name="keywords" content="hello, world" /&gt;
623
+ &lt;meta name="description" content="hello world sample usage for XML class" /&gt;
624
+ &lt;/head&gt;
625
+ &lt;body&gt;
626
+ &lt;div id="main"&gt;
627
+ &lt;h1&gt;Hello World&lt;/h1&gt;
628
+ &lt;p&gt;Hello HTML world&lt;/p&gt;
629
+ &lt;p&gt;from XML&lt;/p&gt;
630
+ &lt;/div&gt;
631
+ &lt;/body&gt;
632
+ &lt;/html&gt;</tt></pre>
633
+ </div></div>
634
+ </div>
635
+ </div>
636
+ <div class="sect1">
637
+ <h2 id="_requirements">Requirements</h2>
638
+ <div class="sectionbody">
639
+ <div class="paragraph"><p>NONE</p></div>
640
+ </div>
641
+ </div>
642
+ <div class="sect1">
643
+ <h2 id="_install">Install</h2>
644
+ <div class="sectionbody">
645
+ <div class="sidebarblock">
646
+ <div class="content">
647
+ <div class="paragraph"><p>sudo gem install tiny_xml_builder</p></div>
648
+ </div></div>
649
+ </div>
650
+ </div>
651
+ <div class="sect1">
652
+ <h2 id="_license">License</h2>
653
+ <div class="sectionbody">
654
+ <div class="paragraph"><p>(The MIT License)</p></div>
655
+ <div class="paragraph"><p>Copyright (c) 2010 Alexandru Ungur</p></div>
656
+ <div class="paragraph"><p>Permission is hereby granted, free of charge, to any person obtaining
657
+ a copy of this software and associated documentation files (the
658
+ <em>Software</em>), to deal in the Software without restriction, including
659
+ without limitation the rights to use, copy, modify, merge, publish,
660
+ distribute, sublicense, and/or sell copies of the Software, and to
661
+ permit persons to whom the Software is furnished to do so, subject to
662
+ the following conditions:</p></div>
663
+ <div class="paragraph"><p>The above copyright notice and this permission notice shall be
664
+ included in all copies or substantial portions of the Software.</p></div>
665
+ <div class="paragraph"><p>THE SOFTWARE IS PROVIDED <em>AS IS</em>, WITHOUT WARRANTY OF ANY KIND,
666
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
667
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
668
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
669
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
670
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
671
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p></div>
672
+ </div>
673
+ </div>
674
+ </div>
675
+ <div id="footnotes"><hr /></div>
676
+ <div id="footer">
677
+ <div id="footer-text">
678
+ Last updated 2011-02-04 14:02:13 EET
679
+ </div>
680
+ </div>
681
+ </body>
682
+ </html>
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bones'
3
+ rescue LoadError
4
+ abort '### Please install the "bones" gem ###'
5
+ end
6
+
7
+ task :default => 'test:run'
8
+ task 'gem:release' => 'test:run'
9
+
10
+ ver = `cat version.txt`.strip
11
+
12
+ Bones {
13
+ name 'tiny_xml_builder'
14
+ version ver
15
+ authors 'Alexandru Ungur'
16
+ email 'alexaandru@gmail.com'
17
+ url 'http://rubygems.com/gems/tiny_xml_builder'
18
+ readme_file 'README.asciidoc'
19
+ ignore_file '.gitignore'
20
+ depend_on 'blankslate'
21
+ }
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'blankslate'
3
+
4
+ module TinyXml
5
+ class Builder < BlankSlate
6
+ reveal :respond_to? unless RUBY_VERSION >= '1.9'
7
+ def initialize(opts = {}, &block)
8
+ @xml = []
9
+ @indent_level = opts[:indent_level] || opts['indent_level'] || 0
10
+ @indent_size = opts[:indent_size] || opts['indent_size'] || 2
11
+ block and instance_eval(&block)
12
+ end
13
+
14
+ def <<(xml)
15
+ @xml << xml.to_s
16
+ end
17
+
18
+ def to_s
19
+ @xml.join("\n")
20
+ end
21
+
22
+ def to_ary
23
+ [to_s]
24
+ end
25
+
26
+ def method_missing(tag, *args, &block)
27
+ indent = ' ' * @indent_level * @indent_size
28
+ attributes = args.last && args.last.is_a?(Hash) ? args.pop.inject(''){|acc,(k,v)| acc << " #{k}=\"#{v}\""} : ''
29
+ if block
30
+ @xml << "%s<%s%s>" % [indent, tag, attributes]
31
+ @indent_level += 1; instance_eval(&block); @indent_level -= 1
32
+ @xml << "%s</%s>" % [indent, tag]
33
+ elsif args.empty?
34
+ @xml << "%s<%s%s />" % [indent, tag, attributes]
35
+ else
36
+ args.map{|a| a && Array(a)}.flatten.each do |val|
37
+ @xml << "%s<%s%s>%s</%s>" % [indent, tag, attributes, val, tag]
38
+ end
39
+ end
40
+ self
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,71 @@
1
+ require 'test/unit'
2
+ require 'tiny_xml_builder'
3
+
4
+ class TinyXMLBuilderTest < Test::Unit::TestCase
5
+ def setup
6
+ @xml = TinyXml::Builder.new(:indent_size => (@indent_size = 4))
7
+ end
8
+
9
+ def test_passing_no_params
10
+ assert_equal '<zaza />', "#{@xml.zaza}"
11
+ end
12
+
13
+ def test_passing_a_nil_as_param
14
+ assert_equal '<zaza></zaza>', "#{@xml.zaza nil}"
15
+ end
16
+
17
+ def test_passing_one_param_that_is_a_hash
18
+ assert_equal '<zaza zuzu="zyzy" />', "#{@xml.zaza :zuzu => "zyzy"}"
19
+ end
20
+
21
+ def test_passing_one_simple_param
22
+ assert_equal '<zaza>123</zaza>', "#{@xml.zaza 123}"
23
+ end
24
+
25
+ def test_passing_an_enumerable
26
+ assert_equal "<zaza>1</zaza>\n<zaza>2</zaza>", "#{@xml.zaza 1..2}"
27
+ end
28
+
29
+ def test_passing_multiple_params
30
+ assert_equal "<zaza>1</zaza>\n<zaza>A</zaza>\n<zaza>Z</zaza>", "#{@xml.zaza 1, "A", :Z}"
31
+ end
32
+
33
+ def test_passing_a_simple_param_and_a_hash
34
+ assert_equal '<zaza zuzu="zumzum">123</zaza>', "#{@xml.zaza 123, :zuzu => "zumzum"}"
35
+ end
36
+
37
+ def test_passing_two_simple_params_and_a_hash
38
+ assert_equal %Q|<zaza zuzu="zumzum">123</zaza>\n<zaza zuzu="zumzum">456</zaza>|,
39
+ "#{@xml.zaza 123, 456, :zuzu => "zumzum"}"
40
+ end
41
+
42
+ def test_pushing_xml_directly
43
+ content = '<foo>bar</foo>'
44
+ @xml << content
45
+ assert_equal content, @xml.to_s
46
+ end
47
+
48
+ def test_passing_a_block
49
+ @xml.zuzu(:where => 'Hawaii') {
50
+ whatToDo {
51
+ swim "a lot"
52
+ justLayOnTheBeach
53
+ party { |p|
54
+ p.allNightLong "hoorayyyy", :must_do_this => true
55
+ }
56
+ }
57
+ }
58
+ expects = <<-EOS.strip
59
+ #{' ' * (0 * @indent_size)}<zuzu where="Hawaii">
60
+ #{' ' * (1 * @indent_size)}<whatToDo>
61
+ #{' ' * (2 * @indent_size)}<swim>a lot</swim>
62
+ #{' ' * (2 * @indent_size)}<justLayOnTheBeach />
63
+ #{' ' * (2 * @indent_size)}<party>
64
+ #{' ' * (3 * @indent_size)}<allNightLong must_do_this="true">hoorayyyy</allNightLong>
65
+ #{' ' * (2 * @indent_size)}</party>
66
+ #{' ' * (1 * @indent_size)}</whatToDo>
67
+ #{' ' * (0 * @indent_size)}</zuzu>
68
+ EOS
69
+ assert_equal expects, "#{@xml}"
70
+ end
71
+ end
data/version.txt ADDED
@@ -0,0 +1 @@
1
+ 0.0.3
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tiny_xml_builder
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 3
10
+ version: 0.0.3
11
+ platform: ruby
12
+ authors:
13
+ - Alexandru Ungur
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-10 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: blankslate
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - "="
28
+ - !ruby/object:Gem::Version
29
+ hash: 105
30
+ segments:
31
+ - 2
32
+ - 1
33
+ - 2
34
+ - 3
35
+ version: 2.1.2.3
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: bones
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 27
47
+ segments:
48
+ - 3
49
+ - 6
50
+ - 2
51
+ version: 3.6.2
52
+ type: :development
53
+ version_requirements: *id002
54
+ description: |-
55
+ A very simple XML builder class. +
56
+ I wanted something really simple that I could easily extend myself later on if I needed to. +
57
+ Ironically, in four years since I created and used TinyXml, I never needed to extend it :-)
58
+ I figured, it may as well work for others in that case, so here it is.
59
+ email: alexaandru@gmail.com
60
+ executables: []
61
+
62
+ extensions: []
63
+
64
+ extra_rdoc_files:
65
+ - History.txt
66
+ files:
67
+ - .gitignore
68
+ - History.txt
69
+ - README.asciidoc
70
+ - README.html
71
+ - Rakefile
72
+ - lib/tiny_xml_builder.rb
73
+ - test/test_tiny_xml_builder.rb
74
+ - version.txt
75
+ has_rdoc: true
76
+ homepage: http://rubygems.com/gems/tiny_xml_builder
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --main
82
+ - README.asciidoc
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 3
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ requirements: []
104
+
105
+ rubyforge_project: tiny_xml_builder
106
+ rubygems_version: 1.3.7
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: A very simple XML builder class.
110
+ test_files:
111
+ - test/test_tiny_xml_builder.rb